/*****************************************************************************
Copyright 2006 Kervin L. Pierre
    EMAIL: otlkcon@adevsoft.com

This file is part of Otlkcon.

Otlkcon is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

Otlkcon is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Lesser GNU General Public License for more details.

You should have received a copy of the Lesser GNU General Public License
along with Otlkcon; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*******************************************************************************/

#include "StdAfx.h"
#include "O_IMSProvider.h"
#include "O_IMSLogon.h"
#include "O_ITable.h"
#include "otlkcon_gui.h"

#include "mstore.h"

#include <mspst.h>

extern const IID IID_IMsgStore;

//extern vector<O_IMSPMsgStore *> otlkcon_stores;
extern CRITICAL_SECTION otlkcon_stores_cs;

extern vector<O_IMSProvider *> otlkcon_store_providers;
extern CRITICAL_SECTION otlkcon_store_providers_cs;

extern HWND  otlkcon_eventHwnd;

O_IMSProvider::O_IMSProvider(void)
{
	InitializeCriticalSection(&objectCS);
	databaseHandle  = NULL;
	m_bSpoolerContext = FALSE;
}

O_IMSProvider::~O_IMSProvider(void)
{
}

void O_IMSProvider::Create(otlkcon_memory *m)
{
    cRef = 1;
    memObj = new otlkcon_memory( m );

    // Store globablly so that other providers can
    // get to it.
    otlkcon_store_providers.push_back( this );
}

void O_IMSProvider::Destroy()
{
	;
}

STDMETHODIMP O_IMSProvider::QueryInterface (REFIID riid, void **ppv)
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, L"inside OMSP_QueryInterface.\n");

    *ppv = NULL;

    if( memcmp(&riid, &IID_IUnknown, sizeof(IID)) &&
        memcmp(&riid, &IID_IMSProvider, sizeof(IID)))
    { 
        result = ResultFromScode(E_NOINTERFACE);
        return result;
    }

    AddRef();
    *ppv = (LPVOID)this;

    return result;
}

ULONG STDMETHODCALLTYPE O_IMSProvider::AddRef (void)
{
    return InterlockedIncrement((LONG*)&cRef);
//	return ++cRef;
}

ULONG STDMETHODCALLTYPE O_IMSProvider::Release (void)
{
    ULONG ulRef = InterlockedDecrement((LONG*)&cRef);
	if ( ulRef == 0 )
    {
        Destroy();
    }

    return cRef;
}

STDMETHODIMP O_IMSProvider::Shutdown(ULONG *lpulFlags)
{
  HRESULT result = S_OK;
  /* clean-up here */

  OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, L"inside IMSProvider->Shutdown.\n");

  Validate_IMSProvider_Shutdown(this,lpulFlags);

  OTLKCON_ENTERCRITICALSECTION(&otlkcon_store_providers_cs, "O_IMSProvider::Shutdown");

  //removing provider from the table
  vector<O_IMSProvider*>::iterator iProvider = find(
	  otlkcon_store_providers.begin(),
	  otlkcon_store_providers.end(),
	  this);
//	  otlkcon_store_providers.find(this);

  if(iProvider != otlkcon_store_providers.end())
  {
	  otlkcon_store_providers.erase(iProvider);
  } // if
  else
  {
	  OTLKCON_DEBUGBREAK
  } // else
  OTLKCON_LEAVECRITICALSECTION(&otlkcon_store_providers_cs, "O_IMSProvider::Shutdown");

  return result;
}

STDMETHODIMP O_IMSProvider::Logon(LPMAPISUP lpMAPISup,
  ULONG ulUIParam,
  LPTSTR lpszProfileName,
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulFlags,
  LPCIID lpInterface,
  ULONG *lpcbSpoolSecurity,
  LPBYTE *lppbSpoolSecurity,
  LPMAPIERROR *lppMAPIError,
  LPMSLOGON *lppMSLogon,
  LPMDB *lppMDB            
)
{
    HRESULT result = S_OK;
    LPPROFSECT lpProfileObj = NULL;
    ULONG profPropsCount = 0, res=0;
    LPSPropValue profProps;
    O_IMSLogon  * mslogon;
    O_IMSPMsgStore *msgstore;
    //HKEY hk;
    LPSPropTagArray profTags;
    MAPIUID instanceGuid = {0};  
    SPropValue tmpProps[7] = {0};
    list<O_IMSPMsgStore *>::iterator li;

    vector<otlkcon_account_details *> accounts;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL, 
        L"inside IMSProvider->Logon\n");

   // Validate_IMSProvider_Logon(this,lpMAPISup,ulUIParam,lpszProfileName,
     //       cbEntryID,lpEntryID,ulFlags,lpInterface,lpcbSpoolSecurity,
       //     lppbSpoolSecurity,lppMAPIError,lppMSLogon,lppMDB);

    // First check the interface
    if( lpInterface != NULL &&
       (memcmp(lpInterface, &IID_IUnknown, sizeof(IID)) &&
        memcmp(lpInterface, &IID_IMAPIProp, sizeof(IID)) &&
        memcmp(lpInterface, &IID_IMsgStore, sizeof(IID)) ))
    {
        //We should check that the interface is supported
        OTLKCON_DEBUGBREAK;
    }

    if( ulFlags & MAPI_DEFERRED_ERRORS )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IMSProvider::Logon() : MAPI_DEFERRED_ERRORS set.\n" );
    }
    if( ulFlags & MAPI_UNICODE )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IMSProvider::Logon() : MAPI_UNICODE set.\n" );
    }
    if( ulFlags & MDB_NO_DIALOG )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IMSProvider::Logon() : MAPI_NO_DIALOG set.\n" );
    }
    if( ulFlags & MDB_NO_MAIL )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IMSProvider::Logon() : MAPI_NO_MAIL set.\n" );
    }
    if( ulFlags & MDB_TEMPORARY )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IMSProvider::Logon() : MDB_TEMPORARY set.\n" );
    }
    if( ulFlags & MDB_WRITE )
    {
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IMSProvider::Logon() : MDB_WRITE set.\n" );
    }

	/* TODO: Save that info for the spooler in lpcbSpoolSecurity and lppbSpoolSecurity */
	*lpcbSpoolSecurity = 0;
	*lppbSpoolSecurity = NULL;

    OTLKCON_ENTERCRITICALSECTION(&objectCS, "O_IMSProvider::Logon");
   // OTLKCON_ENTERCRITICALSECTION(&otlkcon_stores_cs);

    // loop through open stores to see if something can be used.
    for( vector<O_IMSPMsgStore *>::iterator i=stores.begin(); i!=stores.end(); ++i )
    {
        msgstore = *i;
        res = 0;
        if( lpEntryID )
            result = msgstore->CompareEntryIDs( sizeof(O_ENTRYID), 
                     (LPENTRYID)msgstore->entryID, cbEntryID, lpEntryID, 0, &res );
        if( !lpEntryID || res == TRUE )
        {
            // If no EntryID was given, then return one that was in the list
            // Also if the EntryID matches, then obviously return that one
            msgstore->AddRef();

            *lppMDB = (LPMDB)msgstore;
            *lppMSLogon = NULL;

            result = S_OK;
            goto logon_end;
        }    
    }

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"Creating message store number %d.\n", stores.size()+1 );

    //O_ITable *tbl = new O_ITable();
    //result = tbl->Test(dbFilename,memObj->lpAllocateBuffer,lpAllocateMore,lpFreeBuffer);

    // Get the profile properties
    result = lpMAPISup->OpenProfileSection(NULL, MAPI_MODIFY, 
        &lpProfileObj);
    if( result != S_OK )
    {
        /* call failed */
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IMSProvider::Logon() : OpenProfileSection failed.\n" );
        result = MAPI_E_UNCONFIGURED;
        goto logon_end;
    }

    memObj->lpAllocateBuffer(CbNewSPropTagArray(8), (LPVOID*)&profTags);
    memset(profTags,0,CbNewSPropTagArray(8));
    profPropsCount = 0;

    profTags->cValues = 7;

    // If any of the following properties exist, we should use those
    // instead of generating new values??  If they do not exist, then
    // generate new values??

	//We don't need to get PR_ENTRYID
	//It is being passed in the lpEntryID parameter
	//profile contains WrappedEntryID
	//lpEntryID parameter contains our store entryID (unwrapped)
//    profTags->aulPropTag[profPropsCount++] = PR_ENTRYID;
    profTags->aulPropTag[profPropsCount++] = PR_PROVIDER_DISPLAY;
    profTags->aulPropTag[profPropsCount++] = PR_MDB_PROVIDER;
    profTags->aulPropTag[profPropsCount++] = PR_RECORD_KEY;
    profTags->aulPropTag[profPropsCount++] = PR_SERVICE_UID;
    profTags->aulPropTag[profPropsCount++] = PR_PROVIDER_UID;
    profTags->aulPropTag[profPropsCount++] = PR_PST_PATH;
	profTags->cValues = profPropsCount;

    O_ENTRYID *profEID = NULL;
    char      *profProviderDisplay = NULL, *dbFilename = NULL;
    MAPIUID   *profMdbProvider = NULL, *profServiceUid = NULL, *profRecordKey = NULL;

    result = lpProfileObj->GetProps(profTags, 0, &profPropsCount, &profProps);
    switch( result )
	{
		case MAPI_W_ERRORS_RETURNED:
		case S_OK:			
            for( ULONG i=0; i<profPropsCount; i++ )
            {
                if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_ENTRYID) )
                {
                    if( PROP_TYPE(profProps[i].ulPropTag) == PT_BINARY )
                    {
                        profEID = (O_ENTRYID*)(profProps[i].Value.bin.lpb);
                    }    
                }
                else if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_PROVIDER_DISPLAY) )
                {
                    if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
                    {
                        profProviderDisplay = _strdup(profProps[i].Value.lpszA);
                    }
                }
                else if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_MDB_PROVIDER) )
                {
                    if( PROP_TYPE(profProps[i].ulPropTag) == PT_BINARY )
                    {
                       profMdbProvider =  (MAPIUID*)(profProps[i].Value.bin.lpb);
                       if( memcmp(profMdbProvider, &otlkcon_mdb_provider_guid, sizeof(MAPIUID)) )
                       {
                           OTLKCON_DEBUGBREAK;
                       }
                    }
                }
                else if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_RECORD_KEY) )
                {
                    if( PROP_TYPE(profProps[i].ulPropTag) == PT_BINARY )
                    {
                        profRecordKey = (LPMAPIUID)(profProps[i].Value.bin.lpb);
                    }
                }
                else if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_SERVICE_UID) )
                {
                    if( PROP_TYPE(profProps[i].ulPropTag) == PT_BINARY )
                    {
                        profServiceUid = (MAPIUID*)(profProps[i].Value.bin.lpb);
                    }
                }
                else if( PROP_ID(profProps[i].ulPropTag) == PROP_ID(PR_PST_PATH) )
                {
                    if( PROP_TYPE(profProps[i].ulPropTag) == PT_STRING8 )
                    {
                        dbFilename = profProps[i].Value.lpszA;
                    }
                }
            }
			break;

		default:
			//Error condition
            // Call failed 
            OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
                L"GetProfileProperties: GetProps failed.\n" );
            result = MAPI_E_UNCONFIGURED;
            goto logon_end;
    }

    int dbFilenameValid = 0;
    result = otlkcon_testDbFilename( dbFilename, 
                                &dbFilenameValid );

    if( dbFilenameValid == 0 )
    {
        // db file not found
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IMAPIProp database file not found.\n" );
        result = MAPI_E_UNCONFIGURED;
        goto logon_end;
    }

    // Testing gui...
    //
    // otlkcon_config *conf = new otlkcon_config((HWND)ulUIParam, memObj );
    // conf->dbFilename = memObj->pWcsdup( L"c:\\otlkcon.ocdb" );
    // result = conf->showGui();

    // TODO:  We should only do the following if we are the first instance 
    //        of the store.  If the store is already open we should addref
    //        on the interface, and return object.

    // create the logon object
    mslogon = new O_IMSLogon();
    mslogon->Create();
    mslogon->lpAllocateBuffer   = memObj->lpAllocateBuffer;
    mslogon->lpAllocateMore     = memObj->lpAllocateMore;
    mslogon->lpFreeBuffer       = memObj->lpFreeBuffer;
    mslogon->lpMAPISup          = lpMAPISup;

    memset(&instanceGuid, 0, sizeof(MAPIUID));

    if( profRecordKey )
    {
        //We got a record key from the profile, may as well use it.
        memcpy(&instanceGuid, profRecordKey, sizeof(MAPIUID));
    }

    // create MsgStore object
    msgstore = new O_IMSPMsgStore();
	//Create() needs the support object
	msgstore->lpMAPISup = lpMAPISup;
    msgstore->ulUIParam = ulUIParam;
    msgstore->logonFlags = ulFlags;
	//Now do the initialization

    if( lpEntryID )
    {
        //FIXME: Review this
//        OTLKCON_DEBUGBREAK;

        profEID = (O_ENTRYID*)lpEntryID;
    }

    if( profEID )
    {
        // FIXME:  Is this EntryID wrapped?

        // We have already check in memory for this object above        
		result = msgstore->Load(dbFilename, profEID, memObj);
        if( result == MAPI_E_CORRUPT_DATA )
        {
            // TODO:  The database file or store object is corrupt.
            //        Do we need a repair mode or something?
            OTLKCON_DEBUGBREAK;
        }
		else if( result == MAPI_E_NOT_FOUND )
		{
            //We can try to create if the message store did not
            //exist as yet.

			O_ENTRYID* lpOurEntryID	= (O_ENTRYID*)profEID;
			
			result = msgstore->Create(dbFilename, lpOurEntryID->storeInstanceGuid, memObj);
            if( result == MAPI_E_COLLISION )
            {
                // This object exists, but didn't load.
                // Not good....
                OTLKCON_DEBUGBREAK;
            }
		} // if

        if( profRecordKey )
        {
            // FIXME:  We have a record key from the profile
            //         Most likely we will have to change the profile
            //         since all existing objects of this store has
            //         its record key already.
            //OTLKCON_DEBUGBREAK;
        }
    }
    else
    {
        result = msgstore->Create(dbFilename, instanceGuid, memObj);
    }

    if ( FAILED(result) )
    {
        /* call failed */
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"IMSProvider : message store create/load failed : %d.\n", result);
        result = MAPI_E_UNCONFIGURED;
        OTLKCON_DEBUGBREAK;
        goto logon_end;
    }

    lpMAPISup->AddRef();

    // There should be a 1-to-1 relationship between these 2 objects
    mslogon->lpMsgStoreObj = msgstore;
 
    //TESTING: events...
    //{
    //otlkcon_event_struct event  = {0};
    //for(int i=0;i<5;i++)
    //{
    //    event.objectId = msgstore->objectId;
    //    event.objectType = MAPI_STORE;
    //    event.cbData = 1;
    //    event.data[0]  = 1+(rand()%254);
    //    result = otlkcon_event_sendmessage( otlkcon_eventHwnd, otlkcon_eventHwnd, &event );
    //    Sleep(10000);
    //}
    //}

	// Set any profiles properties needed.
	SPropValue tempProps[8] = {0};
    //update profile if we need that
	if(NULL == profEID)
    {

		//FIXME: This may cause conflict between multiple msgstore instances
		tempProps[0].ulPropTag = PR_RECORD_KEY;
		tempProps[0].Value.bin.lpb = (LPBYTE)(profRecordKey?profRecordKey:&(msgstore->entryID->storeInstanceGuid));

        tempProps[0].Value.bin.cb  = sizeof(MAPIUID);

		tempProps[1].ulPropTag = PR_PST_PATH;
		tempProps[1].Value.lpszA = dbFilename;

		//We need to set entryID
		//to open existing store
		SBinary sbStoreEntryID;
		sbStoreEntryID.cb = sizeof(O_ENTRYID);
		sbStoreEntryID.lpb = (LPBYTE)msgstore->entryID;

		SBinary sbWrappedEntryID;
		
		result = lpMAPISup->WrapStoreEntryID(
			sbStoreEntryID.cb,
			(LPENTRYID)sbStoreEntryID.lpb,
			&sbWrappedEntryID.cb,
			(LPENTRYID*)&sbWrappedEntryID.lpb);
		
		if(SUCCEEDED(result))
		{
			tempProps[2].ulPropTag = PR_ENTRYID;
			tempProps[2].Value.bin = sbWrappedEntryID;

			tempProps[3].ulPropTag = PR_STORE_ENTRYID;
			tempProps[3].Value.bin = sbWrappedEntryID;
			
			tempProps[4].ulPropTag = PR_MDB_PROVIDER;
			tempProps[4].Value.bin.lpb = (LPBYTE)&otlkcon_mdb_provider_guid;
			tempProps[4].Value.bin.cb  = sizeof(MAPIUID);
			
			result = lpProfileObj->SetProps(5, tempProps, NULL);
			
			memObj->lpFreeBuffer(sbWrappedEntryID.lpb);
			//No need that profile section is not transacted object
//			result = lpProfileObj->SaveChanges(0);
		} // if
    } // if
	if(NULL != lpProfileObj)
	{
		lpProfileObj->Release();
		lpProfileObj = NULL;
	} // if

    if(SUCCEEDED(result))
    {
		//Add a row to the status table
		memset(&tempProps, 0, sizeof(tempProps));

		/* TODO: Put distinguishing information, eg. a file path in DISPLAY_NAME */
		/* TODO: This should be conditional */
		tempProps[0].ulPropTag = PR_DISPLAY_NAME;
		tempProps[0].Value.lpszA = OTLKCON_STORE_DISPLAY_NAME_A;

		//FIXME: This should be done in O_IMSPMsgStore::Create()
		msgstore->_IntSetProps(1, tempProps, NULL);

		tempProps[1].ulPropTag = PR_PROVIDER_DISPLAY;
		tempProps[1].Value.lpszA = profProviderDisplay?profProviderDisplay:"OpenConnector";

		tempProps[2].ulPropTag = PR_STATUS_CODE;
		tempProps[2].Value.l = STATUS_AVAILABLE;

		tempProps[3].ulPropTag = PR_RESOURCE_METHODS;
		tempProps[3].Value.l = 0;

		tempProps[4].ulPropTag = PR_STATUS_STRING;
		tempProps[4].Value.lpszA = "Available";

		tempProps[5].ulPropTag = PR_MDB_PROVIDER;
		tempProps[5].Value.bin.lpb = (LPBYTE)&otlkcon_mdb_provider_guid;
		tempProps[5].Value.bin.cb  = sizeof(MAPIUID);
		
		tempProps[6].ulPropTag = PR_OBJECT_TYPE;
		tempProps[6].Value.l = MAPI_STATUS;
		
		tempProps[7].ulPropTag = PR_RESOURCE_FLAGS;
		tempProps[7].Value.l = 0;

		result = lpMAPISup->ModifyStatusRow( 8, tempProps, 0 );
    } // if
    
	if( FAILED(result) )
    {
        OTLKCON_DEBUGBREAK
        OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO,  OTLKCON_LOG_TARGET_ALL, 
            L"ERROR: result == %x", result );
        
        // TODO: cleanup, build error struct 
        result = MAPI_E_FAILONEPROVIDER;
        goto logon_end;
    }

    lpMAPISup->SetProviderUID( &(msgstore->entryID->storeInstanceGuid) , 0);

    if(profRecordKey)
    {
		lpMAPISup->ModifyProfile(ulFlags & MDB_TEMPORARY);
    } // if

    *lppMSLogon = (LPMSLOGON)mslogon;
    *lppMDB     = (LPMDB)msgstore;
	
	//that for spooler logon
	//we need that context for Transport provider
	*lpcbSpoolSecurity = sizeof(ULONG);
	*lppbSpoolSecurity = (LPBYTE)memObj->malloc(sizeof(ULONG));
	
	//That is for MSLogon
	msgstore->AddRef();

    // add to the list
	AddLoggedStore(msgstore);
//    stores.push_back( msgstore );

logon_end:
    switch(result)
    {
        case S_OK:
            OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL, 
                    L"leaving IMSProvider::Logon()\n\n" );
            break;

        case MAPI_E_UNCONFIGURED:
            OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL, 
                L"WARNING: leaving IMSProvider::Logon() unconfigured.\n\n" );
            break;

        default:
            OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL, 
                L"ERROR: **** IMSProvider::Logon() failed ****\n\n" );
    }

    //OTLKCON_LEAVECRITICALSECTION(&otlkcon_stores_cs);

    OTLKCON_LEAVECRITICALSECTION(&objectCS, "O_IMSProvider::Logon");
    return result;
}

STDMETHODIMP O_IMSProvider::SpoolerLogon(LPMAPISUP lpMAPISup,
	ULONG ulUIParam,
	LPTSTR lpszProfileName,
	ULONG cbEntryID,
	LPENTRYID lpEntryID,
	ULONG ulFlags,
	LPCIID lpInterface,
	ULONG cbSpoolSecurity,
	LPBYTE lpbSpoolSecurity,
	LPMAPIERROR * lppMAPIError,
	LPMSLOGON * lppMSLogon,
	LPMDB * lppMDB
)
{
    HRESULT result = S_OK;

    OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_SPECIAL_1, OTLKCON_LOG_TARGET_ALL, 
                                        L"inside IMSProvider->SpoolerLogon.\n");

    result = this->Logon(lpMAPISup, ulUIParam, lpszProfileName, cbEntryID, lpEntryID, ulFlags,
                            lpInterface, &cbSpoolSecurity, &lpbSpoolSecurity, lppMAPIError,
                            lppMSLogon, lppMDB );

    m_bSpoolerContext = TRUE;

    return result;
}

STDMETHODIMP O_IMSProvider::CompareStoreIDs( ULONG cbEntryID1, 
	LPENTRYID	lpEntryID1,
	ULONG		cbEntryID2,
	LPENTRYID	lpEntryID2,
	ULONG		ulFlags,
	ULONG *		lpulResult)
{
	HRESULT hResult = E_INVALIDARG;
	*lpulResult = FALSE;
	OTLKCON_LOG_PRINTF(OTLKCON_LOG_LEVEL_INFO, OTLKCON_LOG_TARGET_ALL, 
		L"inside IMSProvider->CompareStoreIDs.\n");

	Validate_IMSProvider_CompareStoreIDs(this,cbEntryID1,lpEntryID1,
		cbEntryID2,lpEntryID2,ulFlags,lpulResult);

	if(NULL != lpEntryID1 && NULL != lpEntryID2) 
	{
		if(sizeof(O_ENTRYID) == cbEntryID1 &&
			sizeof(O_ENTRYID) == cbEntryID2) 
		{
			O_ENTRYID *id1 = (O_ENTRYID *)lpEntryID1;
			O_ENTRYID *id2 = (O_ENTRYID *)lpEntryID2;
			
			if( 0 == memcmp(&(id1->instanceGuid), &(id2->instanceGuid), sizeof(MAPIUID))
				&& 0 == memcmp(&(id1->typeGuid), &(id2->typeGuid), sizeof(MAPIUID)) )
			{
				hResult = S_OK;
				*lpulResult = TRUE;
			}
		} // if
		else
		{
			hResult = MAPI_E_INVALID_ENTRYID;
		} // else
	} // if

	return hResult;
}

BOOL O_IMSProvider::IsSpoolerContext()
{
	return m_bSpoolerContext;
}

O_IMSPMsgStore * O_IMSProvider::RetrieveStore()
{
	if(0 < stores.size())
	{
		return (O_IMSPMsgStore *)stores[0];
	} // if

	return NULL;
}

void O_IMSProvider::RemoveLoggedStore(O_IMSPMsgStore* lpStore)
{
	OTLKCON_ENTERCRITICALSECTION(&objectCS, "O_IMSProvider::RemoveLoggedStore");

	//removing store from the table
	vector<O_IMSPMsgStore*>::iterator iStore = find(
		stores.begin(),
		stores.end(),
		lpStore);

	if(iStore != stores.end())
	{
		stores.erase(iStore);
		lpStore->m_lpParentProvider = NULL;
	} // if
	else
	{
		OTLKCON_DEBUGBREAK
	} // else
	OTLKCON_LEAVECRITICALSECTION(&objectCS, "O_IMSProvider::RemoveLoggedStore");
}

void O_IMSProvider::AddLoggedStore(O_IMSPMsgStore* lpStore)
{
	OTLKCON_ENTERCRITICALSECTION(&objectCS, "O_IMSProvider::AddLoggedStore");
	lpStore->m_lpParentProvider = this;
	stores.push_back(lpStore);
	
	OTLKCON_LEAVECRITICALSECTION(&objectCS, "O_IMSProvider::AddLoggedStore");
}

